using System;
using NUnit.Framework;
using static Optional.Option;

namespace Optional
{
    public class OptionTests
    {
        public Option<int> some1;
        public Option<int> none;

        public Option<int?> someNullVal;
        public Option<string?> someNullRef;

        [SetUp]
        public void Setup()
        {
            some1 = Some(1);
            none = None;

            someNullVal = Some<int?>(null);
            someNullRef = Some<string?>(null);
        }

        [Test]
        public void DefaultEqualsNoneTest()
        {
            Assert.IsTrue(None == default(Option<int>));
            Assert.IsTrue(None == default(Option<int?>));
            Assert.IsTrue(None == default(Option<string>));
            Assert.IsTrue(None == default(Option<string?>));
        }

        [Test]
        public void ValueEqualsTest()
        {
            Assert.IsTrue(some1.Equals(new Option<int>(1)));
            Assert.IsTrue(some1.Equals(1));
            Assert.IsTrue(some1 == new Option<int>(1));
            Assert.IsTrue(some1 == 1);
        }

        [Test]
        public void NullableValueEqualsTest()
        {
            Assert.IsTrue(someNullVal.Equals(new Option<int?>(null)));
            Assert.IsTrue(someNullVal.Equals(null));
            Assert.IsTrue(someNullVal == new Option<int?>(null));
            Assert.IsTrue(someNullVal == null);
        }

        [Test]
        public void NullableReferenceEqualsTest()
        {
            Assert.IsTrue(someNullRef.Equals(new Option<string?>(null)));
            Assert.IsTrue(someNullRef.Equals(null));
            Assert.IsTrue(someNullRef == new Option<string?>(null));
            Assert.IsTrue(someNullRef == null);
        }

        [Test]
        public void SomeToDoTest()
        {
            int i = 0;
            some1.Do(it => i += 2);
            Assert.AreEqual(2, i);

            var j = some1.Do(it => 2);
            Assert.IsTrue(j == 2);
        }

        [Test]
        public void NoneToDoTest()
        {
            int i = 0;
            none.Do(it => i += 2);
            Assert.AreEqual(0, i);

            var j = none.Do(it => 1);
            Assert.IsTrue(j == None);
        }

        [Test]
        public void SomeElseDoTest()
        {
            var i = some1.ElseDo(() => 2);
            Assert.IsTrue(i == None);
        }

        [Test]
        public void NoneElseDoTest()
        {
            var i = none.ElseDo(() => 2);
            Assert.IsTrue(i == 2);
        }

        [Test]
        public void SomeOrTest()
        {
            var i = some1.Or(2);
            Assert.AreEqual(1, i);
        }

        [Test]
        public void NoneOrTest()
        {
            var i = none.Or(2);
            Assert.AreEqual(2, i);

            var j = none.Or(() => 2);
            Assert.AreEqual(2, j);
        }
    }
}